/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package compilador.analisador;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;

/**
 *
 * @author Deivide
 */
public class Lexico {

    DescricaoRegular desc;
    private HashMap<Integer, Token> symbol_table = null;
//    LinkedList tokens;
//    ArrayList<Integer> Linhas;
    private String codigo;
    private final String sinais = "+-/*";

    public Lexico() {}
//    {
//        this.tokens=new LinkedList<String>();
//        this.Linhas=new ArrayList<Integer>();
//    }
    
    public void addToken(String token, EnumTypeToken type, Integer line_num) {
        if (this.symbol_table != null) {
            this.symbol_table.put(this.symbol_table.size(), new Token(token, type, line_num));
        } else {
            this.symbol_table = new HashMap<Integer, Token>();
            this.symbol_table.put(0, new Token(token, type, line_num));
        }
    }
    
    public Token getToken(Integer key) {
        return this.symbol_table.get(key);
    }

    public void pegaTokens(String linha, int nroLinha)
    {
        String[] id=new String[100];
        StringBuffer tok=null;
        int x=0;
        tok=new StringBuffer("                                                                                                                         ");
        StringBuffer tokAux=new StringBuffer("                                                                                                         ");
        int i=0,j=0,k=0,boo=0;
        while (i<linha.length())
        {
//            System.out.print(linha.charAt(i));
            if (linha.charAt(i)=='\'')
            {
                tokAux.setCharAt(0, '\'');
                int l=1;
                i++;
                while (linha.charAt(i)!='\'')
                {
                    tokAux.setCharAt(l, linha.charAt(i));
                    l++;
                    i++;
                }
                tokAux.setCharAt(l, '\'');
                tokAux.setLength(l+1);
                id[j]=tokAux.toString();
                //System.out.println(id[j]);
//                this.tokens.add(id[j]);
//                this.Linhas.add(nroLinha);
                this.addToken(id[j], EnumTypeToken.NADA, nroLinha);
                j++;
                tokAux=new StringBuffer("                                                                                                             ");
            }
            if ((linha.charAt(i)!=' ') && (linha.charAt(i)!='\n') && (linha.charAt(i)!='\'') && (linha.charAt(i) != ',') && (linha.charAt(i) != ';')
                    && (linha.charAt(i) != ':') && (linha.charAt(i) != '(') && (linha.charAt(i) != ')') && (linha.charAt(i) != '+') &&
                    (linha.charAt(i) != '/') && (linha.charAt(i) != '-') && (linha.charAt(i) != '*'))
            {
                tok.setCharAt(k,linha.charAt(i));
                k++;
            }
            if ((linha.charAt(i) == ' ') || (linha.charAt(i) == '\n') || (linha.charAt(i) == ',') || (linha.charAt(i) == ';') || 
                    (linha.charAt(i) == ':') || (linha.charAt(i) == '(') || (linha.charAt(i) == ')') || (linha.charAt(i) == '+') || 
                    (linha.charAt(i) == '/') || (linha.charAt(i) == '-') || (linha.charAt(i) == '*'))
            {
                        if (linha.charAt(i)==',')
                        {
                            boo = 1;
                            //tok.setLength(k-1);
                        }
                        else
                        if (linha.charAt(i)==';')
                        {
                            boo = 2;
                            //tok.setLength(k-1);
                        }
                        else if((linha.charAt(i) == ':') || ((linha.charAt(i) == ':') && (linha.charAt(i+1) == '=')))
                        {
                            boo = 3;
                            if (linha.charAt(i+1) == '=')
                            {
                                i++;
                                x=1;
                            }
                            //tok.setLength(k-1);
                        }
                        else if(linha.charAt(i) == '(')
                        {
                            boo = 4;
                            //tok.setLength(k-1);
                        }
                        else if(linha.charAt(i) == ')')
                        {
                            boo = 5;
                            //tok.setLength(k-1);
                        }
                        else if(linha.charAt(i) == '+')
                        {
                            boo = 6;
                            //tok.setLength(k-1);
                        }
                        else if(linha.charAt(i) == '/')
                        {
                            boo = 7;
                            //tok.setLength(k-1);
                        }
                        else if(linha.charAt(i) == '-')
                        {
                            boo = 8;
                            //tok.setLength(k-1);
                        }
                        else if(linha.charAt(i) == '*')
                        {
                            boo = 9;
                            //tok.setLength(k-1);
                        }
                        if ((tok.charAt(0)!=' ') && (tok.charAt(0)!='\n'))
                        {
                            tok.setLength(k);
                            id[j] = tok.toString();
                            //System.out.println(id[j]);
//                            this.tokens.add(id[j]);
//                            this.Linhas.add(nroLinha);
                            this.addToken(id[j], EnumTypeToken.NADA, nroLinha);
                            j++;
                            k=0;
                            tok=new StringBuffer("                                                                                                                 ");
                        }
                if (boo == 1)
                    {
                        boo=0;
                        tokAux.setCharAt(0, ',');
                        tokAux.setLength(1);
                        id[j]=tokAux.toString();
                        //System.out.println(id[j]);
//                        this.tokens.add(id[j]);
//                        this.Linhas.add(nroLinha);
                        this.addToken(id[j], EnumTypeToken.NADA, nroLinha);
                        j++;
                        tokAux=new StringBuffer("                                                                                                     ");
                    }
                    if (boo==2)
                    {
                        boo=0;
                        tokAux.setCharAt(0, ';');
                        tokAux.setLength(1);
                        id[j]=tokAux.toString();
                        //System.out.println(id[j]);
//                        this.tokens.add(id[j]);
//                        this.Linhas.add(nroLinha);
                        this.addToken(id[j], EnumTypeToken.NADA, nroLinha);
                        j++;
                        tokAux=new StringBuffer("                                                                                                   ");
                    }
                    if (boo==3)
                    {
                        boo=0;
                        if (x==1)
                        {
                            tokAux.setCharAt(0, ':');
                            tokAux.setCharAt(1, '=');
                            tokAux.setLength(2);
                        }
                        else
                        {
                            tokAux.setCharAt(0, ':');
                            tokAux.setLength(1);
                        }
                        id[j]=tokAux.toString();
                        //System.out.println(id[j]);
//                        this.tokens.add(id[j]);
//                        this.Linhas.add(nroLinha);
                        this.addToken(id[j], EnumTypeToken.NADA, nroLinha);
                        j++;
                        tokAux=new StringBuffer("                                                                                                   ");
                    }
                    if (boo==4)
                    {
                        boo=0;
                        tokAux.setCharAt(0, '(');
                        tokAux.setLength(1);
                        id[j]=tokAux.toString();
                        //System.out.println(id[j]);
//                        this.tokens.add(id[j]);
//                        this.Linhas.add(nroLinha);
                        this.addToken(id[j], EnumTypeToken.NADA, nroLinha);
                        j++;
                        tokAux=new StringBuffer("                                                                                                   ");
                    }
                    if (boo==5)
                    {
                        boo=0;
                        tokAux.setCharAt(0, ')');
                        tokAux.setLength(1);
                        id[j]=tokAux.toString();
                        //System.out.println(id[j]);
//                        this.tokens.add(id[j]);
//                        this.Linhas.add(nroLinha);
                        this.addToken(id[j], EnumTypeToken.NADA, nroLinha);
                        j++;
                        tokAux=new StringBuffer("                                                                                                   ");
                    }
                        if (boo==6)
                    {
                        boo=0;
                        tokAux.setCharAt(0, '+');
                        tokAux.setLength(1);
                        id[j]=tokAux.toString();
                        //System.out.println(id[j]);
//                        this.tokens.add(id[j]);
//                        this.Linhas.add(nroLinha);
                        this.addToken(id[j], EnumTypeToken.NADA, nroLinha);
                        j++;
                        tokAux=new StringBuffer("                                                                                                   ");
                    }
                       if (boo==7)
                    {
                        boo=0;
                        tokAux.setCharAt(0, '/');
                        tokAux.setLength(1);
                        id[j]=tokAux.toString();
                        //System.out.println(id[j]);
//                        this.tokens.add(id[j]);
//                        this.Linhas.add(nroLinha);
                        this.addToken(id[j], EnumTypeToken.NADA, nroLinha);
                        j++;
                        tokAux=new StringBuffer("                                                                                                   ");
                    }
                        if (boo==8)
                    {
                        boo=0;
                        tokAux.setCharAt(0, '-');
                        tokAux.setLength(1);
                        id[j]=tokAux.toString();
                        //System.out.println(id[j]);
//                        this.tokens.add(id[j]);
//                        this.Linhas.add(nroLinha);
                        this.addToken(id[j], EnumTypeToken.NADA, nroLinha);
                        j++;
                        tokAux=new StringBuffer("                                                                                                   ");
                    }
                        if (boo==9)
                    {
                        boo=0;
                        tokAux.setCharAt(0, '*');
                        tokAux.setLength(1);
                        id[j]=tokAux.toString();
                        //System.out.println(id[j]);
//                        this.tokens.add(id[j]);
//                        this.Linhas.add(nroLinha);
                        this.addToken(id[j], EnumTypeToken.NADA, nroLinha);
                        j++;
                        tokAux=new StringBuffer("                                                                                                   ");
                    }
            }
            i++;
        }
        if ((tok.charAt(0)!=' ') && (tok.charAt(0)!='\n'))
        {
            tok.setLength(k);
            id[j] = tok.toString();
            //System.out.println(id[j]);
//            this.tokens.add(id[j]);
//            this.Linhas.add(nroLinha);
            this.addToken(id[j], EnumTypeToken.NADA, nroLinha);
        }
    }
    
    public void mostraTokens()
    {
//        int i=0;
//        while (this.tokens.get(i)!=this.tokens.getLast())
//        {
//            System.out.println(this.tokens.get(i));
//            System.out.println(this.Linhas.get(i));
//            i++;
//        }
//        System.out.println(tokens.get(i));
//        System.out.println(this.Linhas.get(i));
        for (int i = 0; i < this.symbol_table.size(); i++) {
            System.out.println(this.symbol_table.get(i).getToken());
            System.out.println(this.symbol_table.get(i).getLineNum());
        }
    }

    public int verificaErrosParenteses()
    {
        int erros=0,i=0,cont1=0,cont2=0,lin=0;
        String x=null;
//        while (this.tokens.get(i)!= this.tokens.getLast())
        while (this.symbol_table.get(i).getToken()!= this.symbol_table.get(this.symbol_table.size() - 1).getToken())
        {
//            x = (String) this.tokens.get(i);
            x = this.symbol_table.get(i).getToken();
            //System.out.println(tokens.get(i));
            if (x.compareTo("(")==0) 
            {
                cont1++;
//                lin=this.Linhas.get(i);
                lin=this.symbol_table.get(i).getLineNum();
            }
            if (x.compareTo(")")==0) 
            {
                cont2++;
                //lin=this.Linhas.get(i);
                lin=this.symbol_table.get(i).getLineNum();
            }
            i++;
        }
         //x=(String) this.tokens.get(i);
        x = this.symbol_table.get(i).getToken();
            if (x.compareTo("(") == 0) 
            {
                cont1++;
//                lin=this.Linhas.get(i);
                lin = this.symbol_table.get(i).getLineNum();
            }
            if (x.compareTo(")") == 0) 
            {
                cont2++;
//                lin=this.Linhas.get(i);
                lin = this.symbol_table.get(i).getLineNum();
            }
        erros=cont1-cont2;
        if (erros!=0) 
        {
            System.out.print("Erro léxico: ");
            if (cont1<cont2)
            {
                System.out.print("Falta(m) ");
                System.out.print(cont2-cont1);
                System.out.print(" caracter(es) \'(' antes da linha ");
                System.out.print(lin);
                System.out.println(".");
            }
            else
                if (cont1 > cont2)
            {
                System.out.print("Falta(m) ");
                System.out.print(cont1-cont2);
                System.out.print(" caracter(es) \'(' antes da linha ");
                System.out.print(lin);
                System.out.println(".");
            }
        }
        return erros;
    }

    public int verificaProgram()
    {
        int erros=0;
        String x=null;
//        x=(String) this.tokens.get(0);
        x = this.symbol_table.get(0).getToken();
        x=x.toLowerCase();
        if (x.compareTo("program")!=0)
                erros++;
        if (erros!=0)
            System.out.println("Erro léxico: Falta o identificador \'program\' no inicio do programa.");
        
        return erros;
    }

    public int verificaVAR()
    {
        int erros=1,i=0;
        String x=null;
//        while (this.tokens.get(i)!=this.tokens.getLast())
        while (this.symbol_table.get(i).getToken() != this.symbol_table.get(this.symbol_table.size() - 1).getToken())
        {
//            x=(String) this.tokens.get(i);
            x = this.symbol_table.get(i).getToken();
            x=x.toLowerCase();
            if (x.compareTo("var")==0)
            {
                erros--;
                break;
            }
            i++;
        }
//        x=(String) this.tokens.get(i);
        x = this.symbol_table.get(i).getToken();
         if (x.compareTo("var")==0)
                erros--;
        if (erros!=-1)
            System.out.println("Erro léxico: Falta o identificador \'var\' no programa.");
        return erros;
    }

    public int verificaVariaveis()
    {
        int erros=0,i=0,cont1=0,cont2=0,lin=0;
        String x=null;
        return erros;
    }

    public void verificaErrosLexicos()
    {
        int nroTotal=0;
        nroTotal=verificaErrosParenteses();
        nroTotal=nroTotal+verificaProgram();
        nroTotal=nroTotal+verificaVAR();
        //AO VERIFICAR AS VARIAVEIS JA GUARDAR NO ARRAYLSIT VARIAVEL \/
        //nroTotal=nroTotal+verificaVariaveis();
        //desc=new DescricaoRegular(this.tokens,this.Linhas);
        if (nroTotal>0)
        {
            System.out.print("Houveram ");
            System.out.print(nroTotal);
            System.out.println(" erros.");
        }
        else System.out.println("Não houveram erros.");
    }

//    public LinkedList retornaTokens()
//    {
//        return this.tokens;
//    }
    
    public HashMap<Integer, Token> getTokens() {
        return this.symbol_table;
    }

//    public ArrayList<Integer> retornaLinhas()
//    {
//        return this.Linhas;
//    }

    public boolean analiseLexica(String fonte) throws FileNotFoundException, IOException
    {
        File f = new File(fonte);
        int nroLinha=-1;
      try
      {
        BufferedReader in = new BufferedReader(new FileReader(f));
        String linha = in.readLine(); //le uma linha
        nroLinha++;
        while(linha != null) {
            //System.out.println(linha);
            nroLinha++;
            pegaTokens(linha,nroLinha);//pega token a token guardando na linkedList tokens
            linha=in.readLine();
        }
        in.close(); //fecha stream
      }
      catch(FileNotFoundException e)
      {
        System.out.println("Arquivo não existe.");
      }
      catch(IOException e)
      {
        System.out.println("Erro na leitura");
      }
        return true;
    }

   /* public Lexico(String cod) {
        this.tokens = new LinkedList<String>();
        //cod = cod.replaceAll(" ", "");
        System.out.println(cod);
        this.codigo = cod;
        //this.separaTokens(cod);
        //System.out.println(this.removeComentariosBloco(this.codigo));
        System.out.println(this.verificaBeginEnd(cod));
    }*/

    public String removeComentariosLinha(String cod) {
        int index_ini = cod.indexOf("//");
        int index_end = index_ini + 2;
        if (index_ini > -1) {
            while (cod.charAt(index_end) != '\n')
                index_end++;
            try {
                cod = cod.replace(cod.substring(index_ini, index_end), "");
            } catch (IndexOutOfBoundsException e) {
                e.printStackTrace();
            }
        }
        return cod;
    }

    public String removeComentariosBloco(String cod) {
        int index_ini = cod.indexOf("/*");
        int index_end = index_ini + 2;
        if (index_ini > -1) {
            while ((cod.charAt(index_end) != '*') || (cod.charAt(index_end + 1) != '/')) {
                if ((cod.charAt(index_end) == '/') && (cod.charAt(index_end + 1) == '*'))
                    cod = cod.replace(cod.subSequence(index_end, cod.length()), removeComentariosBloco(cod.substring(index_end)));
                index_end++;
            }
            try {
                cod = cod.replace(cod.substring(index_ini, index_end + 2), "");
            } catch (IndexOutOfBoundsException e) {
                e.printStackTrace();
            }
        }
        return cod;
    }

    public boolean verificaBeginEnd(String cod) {
        cod = cod.toLowerCase();
        int index = 0;
        int count_begin = 0;
        int count_end = 0;
        // Contagem de begin's.
        while ((index = cod.indexOf("begin")) > -1) {
            count_begin++;
            cod = cod.substring(index + 5);
        }
        index = 0;
        // Contagem de end's.
        while ((index = cod.indexOf("end")) > -1) {
            count_end++;
            cod = cod.substring(index + 3);
        }
        if ((count_begin == count_end) && count_begin > 0)
            return true;
        else
            return false;
    }
}